import 'dart:ui';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:x3_charts_core/model/gradient_line_chart_model.dart';

///**
///* @author hrongyong
///* @date   2/4/21
///* @email hrongyong@gmail.com
///* Description: 渐变折线图
///*/

class GradientLineChartPainter extends CustomPainter {
  List<GradientLineChartModel> chartList;

  ///四周边距
  EdgeInsets padding;

  ///是否绘制Y轴
  bool isDrawYAxis;

  ///是否绘制X轴
  bool isDrawXAxis;

  ///轴线颜色
  Color axisColor;

  ///Y轴标题
  String yAxisTitle;

  ///渐变颜色
  List<Color> linearColor;

  ///渐变系数
  List<double> linearColorStops;

  ///是否需要扩展(自动添加一个起点【x == 0】和终点【x == maxWidth】)
  final bool needToExpand;

  ///是否描边（绘制一根折线覆盖顶部）
  final bool isStroke;

  ///描边颜色
  final Color strokeColor;

  /// 文本Style
  final TextStyle textStyle;

  GradientLineChartPainter({
    @required this.chartList,
    this.padding = const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0, bottom: 20),
    this.isDrawYAxis = false,
    this.isDrawXAxis = true,
    this.axisColor = const Color(0xFFF3F3F3),
    this.linearColor = const [Color(0xFFDA9CB2), Colors.white],
    this.linearColorStops = const [0.5, 1.0],
    this.yAxisTitle = "",
    this.needToExpand = true,
    this.isStroke = false,
    this.strokeColor = Colors.red,
    this.textStyle = const TextStyle(color: Color(0xFF333333), fontSize: 10),
  }) {
    axisPaint = Paint()
      ..color = axisColor
      ..isAntiAlias = true
      ..strokeWidth = 1;
  }

  ///轴线路径
  Path axisPath = Path();
  Paint axisPaint;

  ///最大高度
  double maxHeight = 0.0;

  ///最大宽度
  double maxWidth = 0.0;

  ///每个坐标轴的距离 x 间隔
  double xStep = 0.0;

  ///y 间隔
  double yStep = 0;

  /// 折线点位信息
  final List<Offset> line = [];

  ///折线画笔
  Paint linePaint = Paint()
    ..color = Colors.red
    ..strokeCap = StrokeCap.round
    ..strokeJoin = StrokeJoin.round
    ..style = PaintingStyle.fill;

  ///文字
  final TextPainter _textPainter = TextPainter(textDirection: TextDirection.ltr);

  @override
  void paint(Canvas canvas, Size size) {
    if (chartList.length == 0) return;
    if (needToExpand) chartList.insert(0, GradientLineChartModel(title: "", proportion: chartList[0].proportion));
    if (needToExpand) chartList.add(GradientLineChartModel(title: "", proportion: chartList[chartList.length - 1].proportion));
    maxWidth = size.width - padding.left - padding.right;
    maxHeight = size.height - padding.top - padding.bottom;
    xStep = maxWidth / (chartList.length - 1);
    yStep = maxHeight / 100;
    linePaint
      ..shader = ui.Gradient.linear(
        Offset(size.width / 2, size.height),
        Offset(size.width / 2, 0),
        linearColor,
        linearColorStops,
        TileMode.mirror,
      );

    ///移动画布中心
    canvas.translate(padding.left, size.height - padding.bottom);

    ///绘制Y轴
    drawYAxis(canvas, size);

    ///绘制X轴及文字
    drawXAxisAndText(canvas, size);

    ///收集折线的点
    collectPoints(canvas, size);

    ///绘画渐变折线
    drawLineChart(canvas: canvas, line: line, lineColor: Colors.black);

    ///绘制描边折线
    if (isStroke) drawStrokePolyLinet(canvas: canvas, line: line);

    ///绘制顶上文本
    drawTopText(canvas, size);
  }

  ///绘制描边折线
  drawStrokePolyLinet({@required Canvas canvas, @required List<Offset> line}) {
    canvas.save();

    Path path = Path()..moveTo(line[0].dx, line[0].dy);
    for (var i = 0; i < line.length; i++) {
      if (line[i].dy != -1) {
        path.lineTo(line[i].dx, line[i].dy);
      }
    }

    PathMetrics pms = path.computeMetrics();
    pms.forEach((pm) {
      canvas.drawPath(
          pm.extractPath(0, pm.length),
          Paint()
            ..color = strokeColor
            ..strokeWidth = 2
            ..style = PaintingStyle.stroke);
    });
    canvas.restore();
  }

  /// 绘制顶上文本
  void drawTopText(Canvas canvas, Size size) {
    canvas.save();
    chartList.asMap().keys.forEach((index) {
      if (chartList[index].text != null && chartList[index].text.isNotEmpty) {
        TextSpan text = TextSpan(text: chartList[index].text, style: textStyle);
        _textPainter.text = text;
        _textPainter.layout(); // 进行布局
        Size textSize = _textPainter.size;
        Offset offset = line[index];
        Offset offsetPos = Offset(offset.dx - textSize.width / 2, offset.dy - textSize.height);
        _textPainter.paint(canvas, offsetPos);
      }
    });

    canvas.restore();
  }

  ///还要处理一下起点的问题
  void drawLineChart({@required Canvas canvas, @required List<Offset> line, @required Color lineColor}) {
    canvas.save();

    Path path = Path()..moveTo(0, 0);

    path.lineTo(line[0].dx, line[0].dy);
    for (var i = 1; i < line.length; i++) {
      if (line[i].dy != -1) {
        path.lineTo(line[i].dx, line[i].dy);
      }
    }
    path.lineTo(line[line.length - 1].dx, 0);

    path.close();
    linePaint..strokeWidth = 1;
    linePaint..color = lineColor;
    PathMetrics pms = path.computeMetrics();
    pms.forEach((pm) {
      canvas.drawPath(pm.extractPath(0, pm.length), linePaint);
    });

    canvas.restore();
  }

  void collectPoints(Canvas canvas, Size size) {
    canvas.save();
    line.clear();
    for (int i = 0; i < chartList.length; i++) {
      line.add(_generatePointsOffset(lineValue: chartList[i].proportion, size: size, index: i));
    }
    canvas.restore();
  }

  ///生成点的offset。并且返回列表
  Offset _generatePointsOffset({@required double lineValue, @required Size size, @required int index}) {
    Offset returnOffset;
    double dataHeight = -(lineValue * maxHeight);
    returnOffset = Offset(xStep * index, dataHeight);
    return returnOffset;
  }

  drawYAxis(Canvas canvas, Size size) {
    canvas.save();
    if (this.isDrawYAxis) {
      canvas.drawLine(Offset.zero, Offset(0, -maxHeight), axisPaint);
      TextSpan text = TextSpan(text: yAxisTitle, style: TextStyle(fontSize: 10, color: Color(0xFF333333)));
      _textPainter.text = text;
      _textPainter.layout(); // 进行布局

      Size size = _textPainter.size;

      Offset offsetPos = Offset(size.width / 4, -maxHeight - size.height);
      _textPainter.paint(canvas, offsetPos);
    }
    canvas.restore();
  }

  drawXAxisAndText(Canvas canvas, Size size) {
    canvas.save();
    if (this.isDrawXAxis) {
      canvas.drawLine(Offset.zero, Offset(maxWidth, 0), axisPaint);
      for (int i = 0; i < chartList.length; i++) {
        _drawAxisXText(
          canvas,
          chartList[i].title,
          offset: Offset(0, 4),
        );
        canvas.translate(xStep, 0);
      }
    }
    canvas.restore();
  }

  void _drawAxisXText(Canvas canvas, String str, {Color color = const Color(0xFF868686), FontWeight fontWeight, double fontSize = 12, Offset offset = Offset.zero}) {
    TextSpan text = TextSpan(text: str, style: fontWeight == null ? TextStyle(fontSize: fontSize, color: color) : TextStyle(fontSize: fontSize, color: color, fontWeight: fontWeight));
    _textPainter.text = text;
    _textPainter.layout(); // 进行布局

    Size size = _textPainter.size;

    Offset offsetPos = Offset(offset.dx - size.width / 2, offset.dy);
    _textPainter.paint(canvas, offsetPos);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
